package com.teamwings.modules.code.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.google.common.collect.Lists;
import com.teamwings.api.controller.ApiController;
import com.teamwings.common.aspect.FormControlMap;
import com.teamwings.common.constant.FormConstant;
import com.teamwings.ctrls.FormComponent;
import com.teamwings.modules.code.entity.FormTableCode;
import com.teamwings.modules.code.mapper.FormTableCodeMapper;
import com.teamwings.modules.code.service.IFormTableCodeService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.teamwings.modules.design.vo.FormVo;
import com.teamwings.modules.page.service.IPageService;
import com.teamwings.util.FieldsLoopUtil;
import com.teamwings.util.VoUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.crypto.hash.Hash;
import org.jeecg.common.form.api.vo.FormControlInfoVO;
import org.jeecg.common.form.api.vo.FormInfoDetailVO;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.stereotype.Service;
import java.lang.reflect.InvocationTargetException;
import java.util.*;
import java.util.function.Function;


/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author admin
 * @since 2021-05-06
 */
@Service
public class FormTableCodeServiceImpl extends ServiceImpl<FormTableCodeMapper, FormTableCode> implements IFormTableCodeService {
    @Autowired
    private FormTableCodeMapper formTableCodeMapper;
    @Autowired
    private IPageService pageService;

    @Override
    @Caching(
            evict = {
                    // 清除 FormTableHeadServiceImpl.getById 中的缓存，避免查询最新版本号时出现旧号码
                    @CacheEvict(value = FormConstant.FORM_HEAD_HEAD, key = "{#entity.tableHeadId}"),
                    @CacheEvict(value = FormConstant.FORM_HEAD_CODE, key = "{#entity.tableHeadId, #entity.tableVersion}"),
                    @CacheEvict(value = FormConstant.FORM_HEAD_CODE, key = "{#entity.tableHeadId}")
            }
    )
    public boolean saveOrUpdate(FormTableCode entity) {
        return super.saveOrUpdate(entity);
    }

    @Override
    @Cacheable(value = FormConstant.FORM_HEAD_CODE, key="#formId")
    public FormTableCode getLatestOneByFormId(String formId) {
        return formTableCodeMapper.getLatestOneByFormId(formId);
    }

    @Override
    public List<FormTableCode> getLatestListByFormIds(List<String> formIds) {
        return formTableCodeMapper.getLatestListByFormIds(formIds);
    }

    /**
     * {
     * key => "数据表列名",
     * value => "该列的控件label名称"
     * }
     *
     * @param formId 自定义表单的id
     * @return Map
     */
    @Override
    @Cacheable(value = FormConstant.FORM_HEAD_COLUMN, key = "#formId")
    public List<Map<String, String>> getColumn(String formId) {
        LambdaQueryWrapper<FormTableCode> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(FormTableCode::getTableHeadId, formId);
        queryWrapper.orderByDesc(FormTableCode::getTableVersion);
        queryWrapper.last("limit 1");
        FormTableCode code = formTableCodeMapper.selectOne(queryWrapper);
        String tempTableFields = code.getTableFields();
        // 由小写进行对比
        tempTableFields = tempTableFields.toLowerCase();
        ArrayList<String> tableFields = new ArrayList<>(Arrays.asList(tempTableFields.split(",")));
        ArrayList<Map<String, String>> column = new ArrayList<>();

        Map<String, String> layoutTypeClassMap = FormControlMap.layoutTypeClassMap;
        // 获取所有布局控件的type
        Set<String> layoutTypeList = layoutTypeClassMap.keySet();

        String tableCode = code.getTableCode();
        //FormVo formVo = JSON.parseObject(tableCode, FormVo.class);
        FormVo formVo = VoUtils.newFormVo(tableCode);

        List<FormComponent> formComponentList = formVo.getList();

//        for (FormComponent formComponent : formComponentList) {
//            String type = formComponent.getType();
//            if (layoutTypeList.contains(type)) {
//                String classname = layoutTypeClassMap.get(type);
//                // 实例化布局控件
//                FormComponent layoutFormComponent = this.getFormComponentByClassname(formComponent, classname);
//                // 获取布局里面的普通控件列表
//                List<FormComponent> componentsInTheLayout = layoutFormComponent.getFormComponentList();
//                for (FormComponent componentInTheLayout : componentsInTheLayout) {
//                    String value = componentInTheLayout.getLabel();
//                    String model = componentInTheLayout.getModel();
//                    System.out.println(String.format("获取控件 %s Model 为空。", componentInTheLayout.getLabel()));
//                    if (model == null) {
//                        continue;
//                    }
//                    model = model.toLowerCase();
////                    String key = componentInTheLayout.getKey();
//                    if (tableFields.contains(model)) {
//                        HashMap<String, String> map = new HashMap<>(3);
//                        map.put("type", componentInTheLayout.getType());
////                        map.put("key", StringUtils.isNotEmpty(model) ? model : key);
//                        map.put("key", model);
//                        map.put("value", value);
//                        column.add(map);
//                    }
//                }
//            } else {
//                String value = formComponent.getLabel();
//                String model = formComponent.getModel();
//                model = model.toLowerCase();
////                String key = formComponent.getKey();
//                if (tableFields.contains(model)) {
//                    HashMap<String, String> map = new HashMap<>(3);
//                    map.put("type", formComponent.getType());
////                    map.put("key", StringUtils.isNotEmpty(model) ? model : key);
//                    map.put("key", model);
//                    map.put("value", value);
//                    column.add(map);
//                }
//            }
//        }

//        List<HashMap<String, String>> res = new ArrayList<>();

        // 填充
        FieldsLoopUtil.loop(formVo.getList(), formComponent -> {
            String value = formComponent.getLabel();
            String model = formComponent.getModel();
            String type = formComponent.getType();
            String key = formComponent.getKey().toUpperCase();
            if ((model != null && tableFields.contains(model.toUpperCase()))
                    || tableFields.contains(model) || tableFields.contains(key)) {
                HashMap<String, String> map = new HashMap<>(3);
//                map.put(model, value);
                map.put("key", model);
                map.put("value", value);
                map.put("type", type);
                column.add(map);
//                map.put(StringUtils.isNotEmpty(model) ? model.toUpperCase() : key, value);
            }
        });

//        HashMap<String, String> map = new HashMap<>();
//        map.put("key", "ID");
//        map.put("value", "ID");
        return column;
    }


    /**
     *
     * map内容：
     * {
     *      "字段" => "该字段的控件类型（oa-upload, oa-text...）"
     * }
     *
     * @param formId 自定义表单的id
     * @param hasFormId
     * @return Map
     */
    @Override
    public Map<String, String> getTypeMap(String formId, Boolean hasFormId) {
        if (!hasFormId) {
            List<String> columnList = pageService.getColumnByTableName(formId);
            HashMap<String, String> map = new HashMap<>();
            for (String column : columnList) {
                map.put(column, "oa-text");
            }
            return map;
        }

        LambdaQueryWrapper<FormTableCode> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(FormTableCode::getTableHeadId, formId);
        queryWrapper.orderByDesc(FormTableCode::getTableVersion);
        queryWrapper.last("limit 1");
        FormTableCode code = formTableCodeMapper.selectOne(queryWrapper);
        String tempTableFields = code.getTableFields();
        ArrayList<String> tableFields = new ArrayList<>(Arrays.asList(tempTableFields.split(",")));
        HashMap<String, String> map = new HashMap<>();

        Map<String, String> layoutTypeClassMap = FormControlMap.layoutTypeClassMap;
        // 获取所有布局控件的key
        Set<String> layoutTypeList = layoutTypeClassMap.keySet();

        String tableCode = code.getTableCode();
        //FormVo formVo = JSON.parseObject(tableCode, FormVo.class);
        FormVo formVo = VoUtils.newFormVo(tableCode);

        List<FormComponent> formComponentList = formVo.getList();

        for (FormComponent formComponent : formComponentList) {
            String type = formComponent.getType();
            if (layoutTypeList.contains(type)) {
                String classname = layoutTypeClassMap.get(type);
                // 实例化布局控件
                FormComponent layoutFormComponent = this.getFormComponentByClassname(formComponent, classname);
                // 获取布局里面的普通控件列表
                List<FormComponent> componentsInTheLayout = layoutFormComponent.getFormComponentList();
                for (FormComponent componentInTheLayout : componentsInTheLayout) {
                    String value = componentInTheLayout.getType();

                    String model = componentInTheLayout.getModel();
                    // 没有model的不处理
                    if (model == null) {
                        continue;
                    }
                    model = model.toUpperCase();
                    String key = componentInTheLayout.getKey().toUpperCase();

                    if (tableFields.contains(model) || tableFields.contains(key)) {
                        map.put(StringUtils.isNotEmpty(model) ? model : key, value);
                    }
                }
            } else {
                String value = formComponent.getType();

                String model = formComponent.getModel();
                // 没有model的不处理
                if (model == null) {
                    continue;
                }
                model = model.toUpperCase();
                String key = formComponent.getKey().toUpperCase();
                if (tableFields.contains(model) || tableFields.contains(key)) {
                    map.put(StringUtils.isNotEmpty(model) ? model : key, value);
                }
            }
        }

        return map;
    }


    /**
     *
     * map内容：
     * {
     *      "字段" => "该字段中文名称（客户端传递过来的表单设计中的label）"
     * }
     *
     * @param formId 自定义表单的id
     * @return Map
     */
    @Override
    public Map<String, String> getCnameMap(String formId) {
        LambdaQueryWrapper<FormTableCode> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(FormTableCode::getTableHeadId, formId);
        queryWrapper.orderByDesc(FormTableCode::getTableVersion);
        queryWrapper.last("limit 1");
        FormTableCode code = formTableCodeMapper.selectOne(queryWrapper);
        String tempTableFields = code.getTableFields();
        ArrayList<String> tableFields = new ArrayList<>(Arrays.asList(tempTableFields.split(",")));
        HashMap<String, String> map = new HashMap<>();

        String tableCode = code.getTableCode();
        //FormVo formVo = JSON.parseObject(tableCode, FormVo.class);
        FormVo formVo = VoUtils.newFormVo(tableCode);

        // 填充
        FieldsLoopUtil.loop(formVo.getList(), formComponent -> {
            String value = formComponent.getLabel();
            String model = formComponent.getModel();
            String key = formComponent.getKey().toUpperCase();
            if ((model != null && tableFields.contains(model.toUpperCase()))
                    || tableFields.contains(model) || tableFields.contains(key)) {
                map.put(StringUtils.isNotEmpty(model) ? model.toUpperCase() : key, value);
            }
        });

        return map;
    }

    /**
     * 根据公共控件对象 + classname获取子控件对象同时用一个新的公共控件对象接收这个子控件
     * @param formComponent
     * @param classname
     * @return
     */
    private FormComponent getFormComponentByClassname(FormComponent formComponent, String classname) {
        Class<?> aClass = null;
        try {
            aClass = Class.forName(classname);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        FormComponent component = null;
        try {
            if (aClass != null) {
                component = (FormComponent) aClass.getDeclaredConstructor().newInstance();
            }
        } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
            e.printStackTrace();
        }

        if (component == null) {
            // todo 如果没有实例：1.有可能控件type在后台中不存在 2.其他情况...
        }
        /*
            对象拷贝
                formComponent是客户端传过来的表单控件，
                component是后端根据客户端传过来的类型"type"实例化的对象
         */
        BeanUtils.copyProperties(formComponent, component);
        return component;
    }

    @Override
    @Cacheable(value = FormConstant.FORM_HEAD_CODE, key = "{#formId, #version}")
    public FormTableCode getByFormIdAndVersion(String formId, Integer version) {

        LambdaQueryChainWrapper<FormTableCode> wrapper = new LambdaQueryChainWrapper<>(formTableCodeMapper)
            .eq(FormTableCode::getTableHeadId, formId).orderByDesc(FormTableCode::getId).last("limit 1");
        if (version != null){
            wrapper.eq(FormTableCode::getTableVersion, version);
        }
        return wrapper.one();
    }

    @Override
    public List<FormTableCode> getAllVersionByHeadId(String headId) {
        return new LambdaQueryChainWrapper<>(formTableCodeMapper)
            .eq(FormTableCode::getTableHeadId, headId)
            .select(FormTableCode::getTableVersion)
            .orderByDesc(FormTableCode::getTableVersion)
            .list();
    }

    @Override
    public List<FormTableCode> getCodeWithHead(Wrapper<FormTableCode> wrapper) {
        return formTableCodeMapper.getCodeWithHead(wrapper);
    }

    @Override
    public List<String> getTableCodeWithHeads(Wrapper<FormTableCode> wrapper) {
        return formTableCodeMapper.getTableCodeWithHeads(wrapper);
    }

    @Override
    public Object getAllOrSpecific(String tableHeadId,  Boolean isGetLast, String... columns ) {
        QueryWrapper<FormTableCode> wrapper = new QueryWrapper<FormTableCode>()
            .eq("TABLE_HEAD_ID", tableHeadId)
                .orderByDesc("TABLE_VERSION");
        //判断有没有指定字段
        if (columns != null && columns.length != 0) {
            wrapper.select(columns);
        }
        //是否获取最新的code
        if (isGetLast) {
            wrapper.last("limit 1");
            return formTableCodeMapper.selectOne(wrapper);
        }
        return formTableCodeMapper.selectList(wrapper);
    }

    @Override
    public Map<String, String> getTypeMap(String formId) {
        return getTypeMap(formId, true);
    }

    @Override
    public FormInfoDetailVO getComponentForRecursion(JSONArray jsonList, FormInfoDetailVO detailVo, Function<String, JSONArray> fn){
        ArrayList<String> childsKey = Lists.newArrayList("trs", "tds", "list", "columns");

        jsonList.parallelStream().forEach(item -> {
            FormControlInfoVO formControlInfoVo = new FormControlInfoVO();
            JSONObject jsonObject;

            if (item instanceof JSONObject) {
                jsonObject = (JSONObject) item;
            } else {
                jsonObject = JSONObject.parseObject(item.toString());
            }

            String type = jsonObject.getString("type");

            // 布局控件向下查询
            // 如果有这几个属性，证明结构内还有控件，递归查询
            for (String string : childsKey) {
                if (jsonObject.getString(string) != null) {
                    getComponentForRecursion(JSONArray.parseArray(jsonObject.getString(string)), detailVo, fn);
                }
            }

            // 子表单控件向下查询
            // type=child_form
            if ("child_form".equals(type)) {
                // 查询表单
                String childFormId = null;
                try{
                    childFormId = jsonObject.getJSONObject("options").getString("childFormId");
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
                if (childFormId != null) {
                    JSONArray childList = fn.apply(childFormId);
                    getComponentForRecursion(childList, detailVo, fn);
                }
            }

            formControlInfoVo.setLabel(jsonObject.getString("label"))
                .setValue(jsonObject.getString("key"))
                .setSet(type)
                .setComponentType(jsonObject.getString("componentType"));

            //判断是什么表单控件类型，进行分类封装，没有ComponentType属性的，侧不封装
            if (formControlInfoVo.getComponentType() != null) {
                switch (formControlInfoVo.getComponentType()){
                    case "formBase":
                        detailVo.getFormBaseControls().add(formControlInfoVo);
                        break;
                    case "formButton":
                        detailVo.getFormButtonControls().add(formControlInfoVo);
                        break;
                    case "zhenWen":
                        detailVo.getZhenWenControls().add(formControlInfoVo);
                        break;
                    case "formComment":
                        detailVo.getFormCommentControls().add(formControlInfoVo);
                }
            }
        });

        return detailVo;
    }

}
